/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#ifndef __PHYSICS_H__
#define __PHYSICS_H__


#define MAX_TOUCH_ENTITIES			32

typedef enum {
	PM_NORMAL,									// Can accelerate and turn
	PM_DEAD,									// No acceleration or turning, but free falling
	PM_NOCLIP,									// No gravity and no clipping
	PM_SPECTATOR,								// No gravity but clipped to the world
	PM_FREEZE									// Stuck in place with no control
} pmType_t;

typedef enum {
	PMF_LADDER						= BIT(0),
	PMF_PRONE						= BIT(1),
	PMF_DUCKED						= BIT(2),
	PMF_RESPAWNED					= BIT(3),
	PMF_JUMP_HELD					= BIT(4),
	PMF_TIME_LAND					= BIT(5),
	PMF_TIME_KNOCKBACK				= BIT(6),
	PMF_TIME_WATERJUMP				= BIT(7),
	PMF_ALL_TIMES					= (PMF_TIME_LAND | PMF_TIME_KNOCKBACK | PMF_TIME_WATERJUMP)
} pmFlags_t;

typedef enum {
	WATERLEVEL_NONE,
	WATERLEVEL_FEET,
	WATERLEVEL_WAIST,
	WATERLEVEL_HEAD
} waterLevel_t;

class odPhysicsPlayer {
private:
	// Locals
	float				frameTime;
	int					frameMsec;

	odVec3				viewForward;
	odVec3				viewRight;

	bool				onGround;
	bool				onLadder;

	trace_t				groundTrace;

	bool				ladderForward;
	odVec3				ladderNormal;

	float				impactSpeed;

	odVec3				previousOrigin;
	odVec3				previousVelocity;

	// Callbacks to test the world
	int					(*Contents)(const odVec3 &point, const odBounds &bounds, int contentMask, int passEntityNum);
	trace_t				(*Trace)(const odVec3 &start, const odVec3 &end, const odBounds &bounds, int contentMask, int passEntityNum);

	// Player state (in / out)
	playerState_t *		state;

	// Parameters
	int					moveMsec;

	int					contentMask;

	userCmd_t			userCmd;

	// Results
	odBounds			bounds;

	int					numTouchEntities;
	int					touchEntities[MAX_TOUCH_ENTITIES];

	waterLevel_t		waterLevel;
	int					waterType;

private:
	void				AddTouchEntity (int entityNum);

	void				ClipVelocity (const odVec3 &in, const odVec3 &normal, odVec3 &out, float overBounce);
	void				Friction (void);
	void				Accelerate (const odVec3 &wishDir, float wishSpeed, float accel);

	float				UserCmdScale (void);
	bool				CorrectAllInside (trace_t *trace);

	void				CheckGround (void);
	void				CheckLadder (void);
	void				CheckDuck (void);
	bool				CheckProne (void);
	bool				CheckJump (void);
	bool				CheckWaterJump (void);

	bool				SlideMove (bool gravity);
	void				StepSlideMove (bool grativy);

	void				DeadMove (void);
	void				WalkMove (void);
	void				AirMove (void);
	void				FlyMove (void);
	void				WaterMove (void);
	void				WaterJumpMove (void);
	void				LadderMove (void);
	void				NoclipMove (void);

	void				SetWaterLevel (void);
	void				DropTimers (void);

	void				Move (playerState_t *playerState, int msec);

public:
						odPhysicsPlayer (void);

	void				SetContentsFunction (int (*contents)(const odVec3 &, const odBounds &, int, int));
	void				SetTraceFunction (trace_t (*trace)(const odVec3 &, const odVec3 &, const odBounds &, int, int));

	void				SetMoveMsec (int moveMsec);
	void				SetContentMask (int contentMask);
	void				SetUserCmd (const userCmd_t *userCmd);

	const odBounds &	GetBounds (void) const;

	int					GetNumTouchEntities (void) const;
	int					GetTouchEntity (int index) const;

	waterLevel_t		GetWaterLevel (void) const;
	int					GetWaterType (void) const;

	void				UpdateViewAngles (playerState_t *playerState);
	void				MovePlayer (playerState_t *playerState);
};


#endif	// __PHYSICS_H__
